package com.uxsino.simo.collector.connections;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.uxsino.simo.connections.AbstractConnection;
import com.uxsino.simo.connections.exception.SimoConnectionException;
import com.uxsino.simo.connections.exception.SimoQueryException;
import com.uxsino.simo.connections.target.IPMITarget;

public class IPMIConnection extends AbstractConnection<IPMITarget> {
    private static final Logger logger = LoggerFactory.getLogger(IPMISConnection.class);

    private static final String AUTHTYPE_NONE = "NONE";

    private static final String AUTHTYPE_PASSWORD = "PASSWORD";

    private static final String IPMITOOL = "ipmitool";

    private String utilFilePath = "tools";

    @Override
    public int connect(IPMITarget target) {
        super.connect(target);
        this.target = target;
        this.connected = true;
        state = 1;
        return state;
    }

    @Override
    public String execCmd(Object cmdPattern) throws SimoQueryException, SimoConnectionException {
        Process ipmoProcess = null;
        InputStream is = null;
        StringBuffer result = new StringBuffer();
        try {
            ipmoProcess = Runtime.getRuntime().exec(cmdPattern.toString());
            is = ipmoProcess.getInputStream();
            if (is == null) {
                return null;
            }
            BufferedReader br = new BufferedReader(new InputStreamReader(is));
            String lineStr = null;
            do {
                lineStr = br.readLine();
                if (lineStr != null) {
                    result.append(lineStr + "\n");
                }
            } while (lineStr != null);
            // logger.info("exec ipmi cmd:{}\nresult\n{}", cmdPattern.toString(), result.toString());
            return result.toString();
        } catch (IOException ioe) {
            logger.error("IPMI IO Error. Cmd : {}", cmdPattern, ioe);
        } catch (Exception e) {
            logger.error("IPMI execute exception. Cmd : {}", cmdPattern, e);
        } finally {
            try {
                if (is != null)
                    is.close();
            } catch (Exception e) {
            } finally {
                if (ipmoProcess != null) {
                    ipmoProcess.destroy();
                }
            }
        }
        return null;
    }

    @Override
    public String buildCmd(String cmdPattern, Map<String, String> args) throws SimoQueryException {
        StringBuffer cmd = new StringBuffer();
        String osType = System.getProperty("os.name").toLowerCase();
        if (StringUtils.contains(osType, "windows")) {
            cmd.append(System.getProperty("user.dir")).append(File.separator).append(utilFilePath)
                .append(File.separator);
        }
        cmd.append(IPMITOOL);
        cmd.append(" -I ").append(this.target.getInterf()).append(" -H ").append(this.target.host).append(" -p ")
            .append(this.target.port).append(" -L ").append(this.target.getLevel());
        if (StringUtils.equalsIgnoreCase(this.target.getAuthtype(), AUTHTYPE_NONE))
            cmd.append(" -U ").append(this.target.getUsername());
        else if (StringUtils.equalsIgnoreCase(this.target.getAuthtype(), AUTHTYPE_PASSWORD))
            cmd.append(" -U ").append(this.target.getUsername()).append(" -P ").append(this.target.getPassword());
        else {
            cmd.append(" -U ").append(this.target.getUsername()).append(" -P ").append(this.target.getPassword())
                .append(" -k ").append(this.target.getKGValue());
        }
        cmd.append(" ").append(cmdPattern);
        return cmd.toString();
    }

    @Override
    public int close() {
        this.connected = false;
        super.close();
        return 0;
    }

    @Override
    public boolean testWithConnected(String cmdString, String resStart) {
        connected = false;
        String cmd = "power status";
        String value = null;
        try {
            value = execCmd(buildCmd(cmd, null));
        } catch (SimoQueryException e) {
            logger.error("IPMI test error:{}", cmd, e);
            connected = false;
        } catch (SimoConnectionException e) {
            logger.error("IPMI test error:{}", cmd, e);
            connected = false;
        }
        if (value != null && !value.isEmpty()) {
            connected = true;
        }
        logger.info("{}->connection test result: {}", this.target.host.toString(), connected);
        return connected;
    }

}
